package com.springboot.frame.plugin;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.ResultHandler;
import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

/**
 * 运行Sql和效率插件 <p>
 * <pre>
 * 主要是开发阶段使用,方便查看sql和执行时间
 * </pre>
 *
 * @author liheng
 */
@Intercepts({
    @Signature(type = StatementHandler.class, method = "query", args = {Statement.class,
        ResultHandler.class}),
    @Signature(type = StatementHandler.class, method = "update", args = {Statement.class})})
@Slf4j
public final class SqlPlugin implements Interceptor {

  private static final List<String> SQL_TYPE = Arrays
      .asList("SELECT", "select", "INSERT", "insert", "UPDATE", "update", "DELETE", "delete");

  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    long start = System.currentTimeMillis();
    Object proceed = invocation.proceed();
    StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
    BoundSql boundSql = statementHandler.getBoundSql();
    String sql = boundSql.getSql();
    log.info("mybatis intercept sql:{}", sql);

    long end = System.currentTimeMillis();
    MetaObject metaObject = SystemMetaObject
        .forObject(PluginUtils.realTarget(invocation.getTarget()));
    log.info("执行的方法为 {}",
        ((MappedStatement) metaObject.getValue("delegate.mappedStatement")).getId());
    Object o = PluginUtils.realStatement(invocation.getArgs()[0]);
    String statementSql;
    try {
      Field sqlField = o.getClass().getDeclaredField("sql");
      sqlField.setAccessible(true);
      statementSql = sqlField.get(o).toString();
    } catch (Exception e) {
      statementSql = o.toString();
    }
    log.info("执行的sql耗时 {}毫秒, 完整sql为" + "\n" + "{}", (end - start),
        statementSql.substring(startIndex(statementSql), statementSql.length()));
    return proceed;
  }

  private int startIndex(String statementSql) {
    for (String sqlType : SQL_TYPE) {
      int index = statementSql.indexOf(sqlType);
      if (index > -1) {
        return index;
      }
    }
    return 0;
  }

  @Override
  public Object plugin(Object target) {
    if (target instanceof StatementHandler) {
      return Plugin.wrap(target, this);
    }
    return target;
  }

  @Override
  public void setProperties(Properties properties) {
  }

}
